﻿//
// ArtistPhotoSyncer.cs: Syncs photos to a device.
//
// Copyright 2010 Michael Goethe
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using S9PalCommon;
using S9PalCommon.ArtistLibrary;

namespace LastFMPhotoCrawler
{
    /// <summary>
    /// Syncs photos to a device.
    /// </summary>
    public class ArtistPhotoSyncer : Syncer
    {
        #region Fields

        private const String c_relativeSyncPath = "System\\Flash UI\\Library";
        private Library artistLibrary;
        private Artist resumeArtist = null;

        #endregion

        #region Constructors

        public ArtistPhotoSyncer()
        {
            this.artistLibrary = S9PalCommon.Global.ArtistLibrary;
            this.ItemCategory = "Artist";
            this.Name = "Artist Photo Syncer";
        }

        #endregion

        #region Protected Methods

        /// <summary>
        /// Execute the sync operation.
        /// </summary>
        protected override void OnStart()
        {
            SortedList<String, Artist> artists = artistLibrary.Artists;
            int startIndex = 0;

            // Specify the number of total items so we can calculate the progress.
            ItemCount = artists.Count;

            // If we're resuming from a pause, adjust the start index.
            if (resumeArtist != null)
                startIndex = artists.IndexOfValue(resumeArtist);

            for (int i = startIndex; i < artists.Count; i++)
            {
                // Get the current artist.
                Artist artist = artists.ElementAt(i).Value;

                // Specify the current item so it can be display with the progress.
                CurrentItemName = artist.Name;
                CurrentItemNumber = i + 1;

                // Update the photos for the current artist (if they need to be updated, which is determined in the method).
                UpdatePhotos(artist);

                // Check if the user wants to stop or pause.
                if (Status == WorkerStatus.Stopping)
                {
                    Status = WorkerStatus.Stopped;
                    break;
                }
                if (Status == WorkerStatus.Pausing)
                {
                    resumeArtist = artist;
                    Status = WorkerStatus.Paused;
                    break;
                }
            }

            S9PalCommon.Global.ArtistLibrary.SaveLibrary();
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Updates the photos for an artist.
        /// </summary>
        /// <param name="artist">Artist to update the photos for.</param>
        private void UpdatePhotos(Artist artist)
        {
            List<ArtistPhoto> photos = artist.Photos;
            String purgedArtistName = Helper.RemoveInvalidFileNameCharacters(artist.Name);
            String artistDeviceDirectory = Drive + c_relativeSyncPath + "\\" + purgedArtistName;

            // Delete photos that are either no longer set to sync or need to be updated.
            for (int i = 0; i < photos.Count; i++)
            {
                if (photos[i].NeedsToBeUpdated)
                {
                    // If we have on record that an old file exists, delete that file.
                    if (photos[i].DeviceFileName != null)
                    {
                        File.Delete(artistDeviceDirectory + "\\" + photos[i].DeviceFileName);
                        photos[i].DeviceFileName = null;
                    }

                    // If the photo is not set to sync, we're done, so set NeedsToBeUpdated to false.
                    // Otherwise, we want to leave it set to true so that it can be re-added below.
                    if (!photos[i].SyncPhoto)
                        photos[i].NeedsToBeUpdated = false;
                }
            }

            // Sync photos that need to be added or updated.
            for (int i = 0; i < photos.Count; i++)
            {
                if (photos[i].NeedsToBeUpdated && photos[i].SyncPhoto)
                {
                    String sourcePath = artistLibrary.LibraryDirectory + "\\" + purgedArtistName + "\\" + photos[i].LocalFileName;
                    String destPath = artistDeviceDirectory + "\\" + (i + 1).ToString() + ".jpg";
                    bool retry = false;

                    do
                    {
                        try
                        {
                            // Delete the file at the path we're copying to (if one exists).
                            File.Delete(destPath);
                            // Copy the file from its local home to the device.
                            File.Copy(sourcePath, destPath, true);
                            // Update DeviceFileName so that we can get rid of it later if need be.
                            photos[i].DeviceFileName = Path.GetFileName(destPath);
                            // Update is finished, so reset NeedsToBeUpdated.
                            photos[i].NeedsToBeUpdated = false;

                            retry = false;
                        }
                        catch (DirectoryNotFoundException)
                        {
                            Directory.CreateDirectory(Path.GetDirectoryName(destPath));
                            retry = true;
                        }
                    } while (retry);
                }
            }
        }

        #endregion
    }
}